﻿#include "../../Common/Common.h"

// 1. 首先定义关键的Windows宏，净化windows.h的包含环境
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h> // 先包含windows.h，让它在我们设定的规则下展开

// 2. 接下来是关键的一步：防止gl.h内部的重复定义
// 定义OpenGL API调用的宏，确保它们使用stdcall调用约定
// 这通常是gl.h所期望的
#ifndef APIENTRY
#define APIENTRY __stdcall
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
#ifndef GLAPI
#define GLAPI extern
#endif

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgGA/GUIEventAdapter>
#include <osgViewer/ViewerEventHandlers>
#include <osg/Geode>
#include <osg/StateSet>
#include <osg/ShapeDrawable>
#include <osg/Material>
#include <osg/Image>
#include <osg/Texture2D>
#include <osg/LineWidth>

#include <iostream>

osg::ref_ptr<osg::Geode> CreateBox()
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints;
	osg::ref_ptr<osg::ShapeDrawable> shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 1.0, 10.0, 10.0), hints.get());
	osg::ref_ptr<osg::Material> material = new osg::Material;
	osg::ref_ptr<osg::Texture2D> texture2D = new osg::Texture2D;
	osg::ref_ptr<osg::Image> image;

	// 设置颜色
	shape->setColor(osg::Vec4(0.5, 0.55, 0.5, 0.1));

	// 设置精度
	hints->setDetailRatio(0.5);

	// 设置材质
	material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(1.0, 1.0, 1.0, 0.5));
	material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(1.0, 1.0, 1.0, 0.5));
	material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(1.0, 1.0, 1.0, 0.5));
	material->setShininess(osg::Material::FRONT_AND_BACK, 6.0);

	// 设置纹理
	image = osgDB::readImageFile("/Images/whitemetal_diffuse.jpg");
	if (image.valid())
	{
		texture2D->setImage(image.get());
	}

	geode->getOrCreateStateSet()->setAttributeAndModes(material.get(), osg::StateAttribute::ON); // 状态给到OPENGL
	geode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
	geode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
	geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture2D.get(), osg::StateAttribute::ON);
	geode->addDrawable(shape.get());
	return geode;
}

// 创建简单图元
osg::ref_ptr<osg::Node> CreateSimple()
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;

	// 申请一些顶点
	osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array;
	// 申请颜色
	osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
	// 申请法向量
	osg::ref_ptr<osg::Vec3Array> norms = new osg::Vec3Array;
	// 限制线宽
	osg::ref_ptr<osg::LineWidth> width = new osg::LineWidth;


	geode->addDrawable(geom);

	// 打开透明度
	geode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);

	//设置线宽
	width->setWidth(5.0);
	geode->getOrCreateStateSet()->setAttributeAndModes(width.get(), osg::StateAttribute::ON);
	// 设置顶点
	geom->setVertexArray(coords.get());
	// 设置顶点关联方式
	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::Mode::LINE_LOOP, 0, 4));	// 同一个vertex array里能设置不同的primitve mode。
	// 设置顶点颜色
	geom->setColorArray(colors.get());
	geom->setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX);
	// 设置法向量
	geom->setNormalArray(norms.get());
	geom->setNormalBinding(osg::Geometry::AttributeBinding::BIND_OVERALL);

	// 设置顶点数据 （必须要逆时针）
	coords->push_back(osg::Vec3(-10.0, 5.0, -10.0));
	coords->push_back(osg::Vec3(10.0, 5.0, -10.0));
	coords->push_back(osg::Vec3(10.0, 5.0, 10.0));
	coords->push_back(osg::Vec3(-10.0, 5.0, 10.0));

	// 颜色
	colors->push_back(osg::Vec4f(1.0, 0.0, 0.0, 0.5));
	colors->push_back(osg::Vec4f(0.0, 1.0, 0.0, 0.5));
	colors->push_back(osg::Vec4f(0.0, 0.0, 1.0, 0.5));
	colors->push_back(osg::Vec4f(1.0, 1.0, 0.0, 0.5));

	// 压入一个法向量
	norms->push_back(osg::Vec3(0.0, -1.0, 0.0));

	return geode;

}

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;

	osg::ref_ptr<osg::Group> group = new osg::Group;
	group->addChild(osgDB::readNodeFile("glider.osg"));	// 注意透明的要先渲染
	group->addChild(CreateSimple());	

	viewer->setSceneData(group.get());

	// 设置为单屏幕模式
	viewer->setUpViewInWindow(100, 100, 1920, 1080); // 在主屏幕上创建窗口

	return viewer->run();
}



